<template>
  <el-select
    ref="selectRef"
    v-model="selectedIds"
    v-bind="$attrs"
    :filter-method="selectFilterMethod"
    :clearable="clearable"
    :filterable="filterable"
    @visible-change="selectVisibleChangeHandler"
    @focus="focusHandler"
    @change="selectChangeHandler"
  >
    <el-option disabled class="tree-option" :value="null">
      <el-tree
        ref="treeRef"
        :data="treeData"
        class="tree"
        v-bind="treeOptions"
        :node-key="commonProps.id"
        :props="{
          id:commonProps.id,
          label:commonProps.name,
          children:commonProps.children
        }"
        :filter-node-method="filterNodeMethod"
        :show-checkbox="multiple"
        :default-expand-all="defaultExpandAll"
        :highlight-current="!multiple"
        :expand-on-click-node="multiple || leafOnly"
        @node-expand="nodeExpandHandler"
        @node-collapse="nodeCollapseHandler"
        @node-click="treeClickHandler"
        @check="treeCheckHandler"
      />
    </el-option>
    <!--  将其余的选型隐藏掉  -->
    <el-option
      v-for="item in plainData.filter(e=> multiple? e.isLeaf : ( leafOnly? e.isLeaf:true))"
      v-show="false"
      :key="item[commonProps.id]"
      :value="item[commonProps.id]"
      :label="item[commonProps.name]"
    />
  </el-select>
</template>
<script>

export default {
  name: 'TreeSelect',
  props: {
    value: {
      type: [Array, String, Number],
      default: () => []
    },
    data: {
      type: Array,
      default: () => []
    },
    clearable: {
      type: Boolean,
      default: true
    },
    leafOnly: Boolean,
    treeOptions: {
      type: Object,
      default: () => ({})
    },
    // 下拉为单选时返回数组，默认返回value
    singleSelectEmitArray: {
      type: Boolean,
      default: false
    },
    commonProps: {
      type: Object,
      required: false,
      default() {
        return {
          id: 'value',
          name: 'label',
          children: 'children'
        }
      }
    },
    filterable: {
      type: Boolean,
      default: false
    },
    defaultExpandAll: {
      type: Boolean,
      default: true
    }
  },
  data: () => ({
    treeData: [],
    plainData: [],
    selectedIds: [],
    lastHighlightNodeId: undefined,
    panelScrollTop: 0
  }),
  computed: {
    // commonProps() {
    //   return {
    //     id: 'value',
    //     name: 'label',
    //     children: 'children'
    //   }
    // },
    multiple() {
      return Object.keys(this.$attrs).includes('multiple') && this.$attrs.multiple !== false
    }
  },
  watch: {
    data: {
      handler() {
        this.treeData = this.data
        this.plainData = this.getPlainTreeData(this.data)
        this.panelScrollTop = 0
      },
      deep: true,
      immediate: true
    },
    value: {
      handler() {
        if (this.multiple) {
          // 多选
          this.selectedIds = JSON.parse(JSON.stringify(this.value))
          this.$nextTick(() => {
            this.$refs.treeRef.setCheckedKeys(this.value.filter(value => this.plainData.find(item => item.value === value)?.isLeaf))
          })
        } else {
          // 单选
          if (this.singleSelectEmitArray) {
            this.selectedIds = this.value[0]
          } else {
            this.selectedIds = this.value
          }
          if (this.leafOnly && !this.plainData.find(e => e[this.commonProps.id] === this.selectedIds)?.isLeaf) {
            this.lastHighlightNodeId = undefined
            this.$nextTick(() => {
              this.$refs.treeRef.setCurrentKey(undefined)
            })
          } else {
            this.lastHighlightNodeId = this.selectedIds || undefined
            this.$nextTick(() => {
              this.$refs.treeRef.setCurrentKey(this.selectedIds || undefined)
            })
          }
        }
      },
      deep: true,
      immediate: true
    }

  },
  methods: {
    getPlainTreeData(treeData, result = []) { // 初始化下拉菜单本身的选项
      treeData.forEach(e => {
        const current = {
          [this.commonProps.id]: e[this.commonProps.id],
          [this.commonProps.name]: e[this.commonProps.name]
        }
        result.push(current)
        current.isLeaf = true
        if (e[this.commonProps.children]?.length) {
          this.getPlainTreeData(e[this.commonProps.children], result)
        } else {
          current.isLeaf = true
        }
      })
      return result
    },
    treeClickHandler(val, node) { // 树选中节点（单选时）
      if (!this.multiple) {
        if (this.leafOnly && !node.isLeaf) {
          this.$refs.treeRef.setCurrentKey(this.lastHighlightNodeId)
          return
        }
        this.lastHighlightNodeId = node.id

        this.selectedIds = val[this.commonProps.id]
        this.$refs.selectRef.handleClose()
        if (this.singleSelectEmitArray) {
          this.$emit('input', [this.selectedIds])
        } else {
          this.$emit('input', this.selectedIds)
        }
      }
    },
    treeCheckHandler() { // 树选中节点（多选时）
      if (this.multiple) {
        this.selectedIds = this.$refs.treeRef.getCheckedKeys(true)
        this.$emit('input', [...this.selectedIds])
      }
    },
    selectChangeHandler(values) { // 下拉选中内容改变时
      if (this.multiple) {
        this.$refs.treeRef.setCheckedKeys(values)
      } else {
        this.lastHighlightNodeId = values || undefined
        this.$refs.treeRef.setCurrentKey(values || undefined)
      }
      this.$emit('input', values === '' ? [] : values)
    },
    nodeCollapseHandler() {
      setTimeout(() => {
        this.$refs.selectRef.broadcast('ElSelectDropdown', 'updatePopper')
      }, 10)
    },
    nodeExpandHandler() {
      setTimeout(() => {
        this.$refs.selectRef.broadcast('ElSelectDropdown', 'updatePopper')
      }, 10)
    },
    // 筛选功能相关
    selectFilterMethod(val) {
      this.$refs.treeRef.filter(val)
    },
    filterNodeMethod(val, data) {
      if (!val) {
        return true
      }
      return String(data[this.commonProps.name]).toLowerCase().includes(String(val).toLowerCase())
      // return data[this.commonProps.name].indexOf(val) !== -1
    },
    selectVisibleChangeHandler(isVisible) {
      if (!isVisible) {
        this.panelScrollTop = this.$refs.selectRef.$refs.scrollbar.$el.children[0].scrollTop
      }
      setTimeout(() => {
        this.$refs.treeRef.filter()
      }, 100)
    },
    focusHandler() {
      setTimeout(() => {
        this.$refs.selectRef.$refs.scrollbar.$el.children[0].scrollTo({ top: this.panelScrollTop || 0 })
      })
    }
  }
}
</script>

<style scoped>
.tree-option {
  width: 100%;
  line-height: 0;
  padding: 0 !important;
  height: 100%;
  overflow: auto;
}

.tree {
  font-weight: normal;
  width: 100%;
}

/deep/ .el-tree-node__content {
  padding-right: 10px;
}

/deep/ .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
  font-weight: bold;
  color: #409EFF;
}

/deep/ .el-tree-node__children {
  width: 0;
  overflow: hidden;
}

/deep/ .el-tree-node__children[aria-expanded='true'] {
  position: relative;
  width: 100%;
}

/deep/ .el-select-dropdown__list > * {
  display: none;
}

/deep/ .el-select-dropdown__list > *:first-child {
  display: block;
}
</style>
